from io import BytesIO
from typing import List
from venv import logger

from dateutil.parser import isoparse
from fastapi import APIRouter, Body
from openpyxl.workbook import Workbook
from starlette.responses import StreamingResponse
from tortoise.exceptions import DoesNotExist

from app.schemas.parameter import ParameterCreate, ParameterOut, ParameterDetailOut, ParameterCreateList
from app.crud import parameter as crud_parameter
from app.utils.Result import Result


router = APIRouter()

@router.post(
    "/parameters/",
    response_model=Result[bool],
    summary="创建参数及其多个参数值",
    description="同时创建一条参数记录和对应的一组参数值，values长度需等于granularity"
)
async def create_parameter_api(data: ParameterCreate):
    success = await crud_parameter.create_parameter_with_values(data)
    if success:
        return Result.ok(msg="创建成功")
    else:
        return Result.error(code=400, msg="参数值数量与粒度不符，创建失败")


@router.post(
    "/parameters/create-list",
    response_model=Result[bool],
    summary="创建参数及其多个参数值",
    description="同时创建一条参数记录和对应的一组参数值，values长度需等于granularity"
)
async def create_parameter_api(data: ParameterCreateList):
    success = await crud_parameter.create_parameter_with_values_list(data)
    if success:
        return Result.ok(msg="创建成功")
    else:
        return Result.error(code=400, msg="参数值数量与粒度不符，创建失败")

@router.delete(
    "/parameters/batch",
    response_model=Result[bool],
    summary="批量删除参数",
    description="根据参数ID列表，批量删除参数记录。"
)
async def delete_parameters(parameter_ids: List[int] = Body(..., embed=True, description="要删除的参数ID列表")):
    deleted_count = await crud_parameter.delete_parameters(parameter_ids)
    if deleted_count == 0:
        return Result.error(code=404, msg="删除失败，没有匹配的参数")
    return Result.ok(data=True, msg=f"删除成功，共删除 {deleted_count} 条记录")

@router.delete(
    "/parameters/{parameter_id}",
    response_model=Result[bool],
    summary="删除参数",
)
async def delete_parameter(parameter_id: int):
    success = await crud_parameter.delete_parameter(parameter_id)
    if success:
        return Result.ok(data=True, msg="删除成功")
    else:
        return Result.error(code=404, msg="删除失败，参数不存在")

@router.get(
    "/parameters/{parameter_id}/values",
    response_model=Result[dict],
    summary="获取参数值时间和数值列表",
    description="根据参数ID获取该参数所有时间点和值，返回两个数组：time_list 和 value_list。"
)
async def get_parameter_values_api(parameter_id: int):
    values_dict = await crud_parameter.get_parameter_values(parameter_id)
    if not values_dict["time_list"]:
        return Result.error(code=404, msg="该参数没有对应的参数值")
    return Result.ok(data=values_dict)

@router.get(
    "/category/{category_id}",
    response_model=Result[List[ParameterOut]],
    summary="根据类别ID获取参数列表",
    description="根据参数类别ID查询该类别下所有参数信息"
)
async def list_parameters_by_category_api(category_id: int):
    try:
        params = await crud_parameter.list_parameters_by_category(category_id)
        return Result.ok(data=params)
    except DoesNotExist:
        return Result.error(code=404, msg="未找到对应的参数类别")

@router.get(
    "/parameters",
    response_model=Result[List[ParameterOut]],
    summary="获取所有参数信息",
    description="查询系统中所有的参数列表"
)
async def list_all_parameters_api():
    try:
        params = await crud_parameter.list_all_parameters()
        return Result.ok(data=params)
    except Exception as e:
        # 可以根据需要细化异常处理
        return Result.error(code=500, msg="内部服务器错误")

@router.get(
    "/parameters/detail",
    response_model=Result[List[ParameterDetailOut]],
    summary="获取所有参数信息(带详细信息)",
    description="查询系统中所有的参数列表"
)
async def list_all_parameters_detail_api():
    try:
        params = await crud_parameter.list_all_parameters_detail()
        return Result.ok(data=params)
    except Exception as e:
        # 可以根据需要细化异常处理
        return Result.error(code=500, msg="内部服务器错误")

@router.post(
    "/parameters/detail/by_ids",
    response_model=Result[List[ParameterDetailOut]],
    summary="根据ID列表获取参数详细信息",
    description="传入参数ID列表，查询对应的参数详细信息"
)
async def list_parameters_detail_by_ids_api(param_ids: List[int] = Body(..., embed=True)):
    """
    param_ids 示例请求体：
    {
      "param_ids": [1, 2, 3]
    }
    """
    try:
        params = await crud_parameter.list_parameters_detail_by_ids(param_ids)
        return Result.ok(data=params)
    except Exception as e:
        return Result.error(code=500, msg="内部服务器错误")

@router.get(
    "/category/{category_id}/detail",
    response_model=Result[List[ParameterDetailOut]],
    summary="根据类别ID获取参数列表",
    description="根据参数类别ID查询该类别下所有参数信息"
)
async def list_parameters_by_category_detail_api(category_id: int):
    try:
        params = await crud_parameter.list_parameters_by_category_detail_api(category_id)
        return Result.ok(data=params)
    except DoesNotExist:
        return Result.error(code=404, msg="未找到对应的参数类别")

@router.post(
    "/parameters/detail/export_by_ids",
    summary="根据 ID 列表导出参数详细信息",
    description="传入参数 ID 列表，返回 Excel 文件"
)
async def export_parameters_detail_by_ids_api(param_ids: List[int] = Body(..., embed=True)):
    try:
        params = await crud_parameter.list_parameters_detail_by_ids(param_ids)


        # 创建 Excel
        wb = Workbook()
        ws = wb.active
        ws.title = "参数详情"

        # 表头（你可以根据实际字段修改）
        ws.append(["参数类别ID", "参数名", "单位", "值", "时间点"])

        for param in params:
            for time_str, val in zip(param["time_list"], param["value_list"]):
                ws.append([
                    param["category_id"],
                    param["parameter_name"],
                    "",  # 如果你这里要填别的内容，也可以改
                    val,
                    time_str.replace(tzinfo=None).isoformat()
                ])

        # 写入流
        stream = BytesIO()
        wb.save(stream)
        stream.seek(0)

        return StreamingResponse(
            stream,
            media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            headers={"Content-Disposition": "attachment; filename=parameters_export.xlsx"}
        )

    except Exception as e:
        logger.error(f"导出参数时发生错误: {e}")
        return StreamingResponse(BytesIO("导出失败".encode("utf-8")), media_type="text/plain", status_code=500)